const fs = require('fs');
const path = require('path');
const dayjs = require('dayjs');
const weekOfYear = require('dayjs/plugin/weekOfYear');
const simpleGit = require('simple-git');
const ExcelJS = require('exceljs');

dayjs.extend(weekOfYear);

// 读取配置
function readConfig() {
  try {
    const configPath = path.join(__dirname, 'config.json');
    const configData = fs.readFileSync(configPath, 'utf8');
    return JSON.parse(configData);
  } catch (error) {
    console.error('读取配置文件失败:', error.message);
    process.exit(1);
  }
}

// 计算当前年份和周数
function calculateDateInfo() {
  const now = dayjs();
  const year = now.format('YYYY');
  const week = now.week();
  return { year, week };
}

// 生成文件名
function generateFileName(config, dateInfo) {
  const { deptName, name } = config;
  const { year, week } = dateInfo;
  return `${deptName}_成员周报_${name}_${year}第${week}周.xlsx`;
}

// 检查文件是否存在并执行操作
function processWeeklyReport(startDate = null, endDate = null) {
  // 读取配置
  const config = readConfig();
  
  // 计算日期信息
  let dateInfo;
  if (startDate && endDate) {
    // 如果指定了日期范围，计算该范围内的周数
    const start = dayjs(startDate);
    const end = dayjs(endDate);
    const weeks = [];
    
    // 获取开始日期所在周
    let currentWeek = start.startOf('week');
    
    // 遍历所有周，直到结束日期
    while (currentWeek.isBefore(end) || currentWeek.isSame(end, 'week')) {
      const weekStart = currentWeek.format('YYYY-MM-DD');
      const weekEnd = currentWeek.endOf('week').format('YYYY-MM-DD');
      
      // 如果这一周与指定日期范围有交集，则包含
      // 修改判断条件，确保包含周六和周日的提交记录
      if ((dayjs(weekEnd).isSame(start) || dayjs(weekEnd).isAfter(start)) && (dayjs(weekStart).isSame(end) || dayjs(weekStart).isBefore(end))) {
        weeks.push({
          year: currentWeek.format('YYYY'),
          week: currentWeek.week(),
          startDate: weekStart,
          endDate: weekEnd
        });
      }
      
      currentWeek = currentWeek.add(1, 'week');
    }
    
    return weeks.map(weekInfo => {
      const fileName = generateFileName(config, weekInfo);
      const outputDir = path.join(__dirname, 'output');
      
      if (!fs.existsSync(outputDir)) {
        fs.mkdirSync(outputDir, { recursive: true });
      }
      
      const templateFile = path.join(__dirname, 'template', 'deptName_成员周报_name_YYYY第week周.xlsx');
      const outputFile = path.join(outputDir, fileName);
      
      // 复制模板文件到输出目录并重命名
      try {
        fs.copyFileSync(templateFile, outputFile);
        console.log(`成功创建周报文件: ${outputFile}`);
        return {
          filePath: outputFile,
          weekInfo: weekInfo
        };
      } catch (error) {
        console.error('创建周报文件失败:', error.message);
        return null;
      }
    }).filter(Boolean);
  } else {
    // 原有的逻辑：生成当前周的文件
    dateInfo = calculateDateInfo();
    const fileName = generateFileName(config, dateInfo);
    const outputDir = path.join(__dirname, 'output');
    
    if (!fs.existsSync(outputDir)) {
      fs.mkdirSync(outputDir, { recursive: true });
    }
    
    const templateFile = path.join(__dirname, 'template', 'deptName_成员周报_name_YYYY第week周.xlsx');
    const outputFile = path.join(outputDir, fileName);
    
    if (fs.existsSync(outputFile)) {
      console.log(`文件已存在: ${outputFile}`);
      return [{
        filePath: outputFile,
        weekInfo: dateInfo
      }];
    }
    
    try {
      fs.copyFileSync(templateFile, outputFile);
      console.log(`成功创建周报文件: ${outputFile}`);
      return [{
        filePath: outputFile,
        weekInfo: dateInfo
      }];
    } catch (error) {
      console.error('创建周报文件失败:', error.message);
      return [];
    }
  }
}

/**
 * 创建每日工作记录txt文件
 * @param {object} config - 配置对象
 * @param {object} projectCommits - 按项目分组的提交记录
 */
function createDailyTxtFiles(config, projectCommits) {
  try {
    // 创建txt文件输出目录
    const txtOutputDir = path.join(__dirname, 'daily_reports');
    if (!fs.existsSync(txtOutputDir)) {
      fs.mkdirSync(txtOutputDir, { recursive: true });
    }
    
    // 处理提交记录，按日期分组
    const commitsByDate = {};
    
    // 遍历每个项目的提交记录
    Object.keys(projectCommits).forEach(projectName => {
      const projectCommitsList = projectCommits[projectName];
      
      projectCommitsList.forEach(commit => {
        // 从提交记录中提取日期
        const dateMatch = commit.message.match(/\[(\d{4}-\d{2}-\d{2})/);
        if (dateMatch) {
          const commitDate = dateMatch[1];
          if (!commitsByDate[commitDate]) {
            commitsByDate[commitDate] = {};
          }
          if (!commitsByDate[commitDate][projectName]) {
            commitsByDate[commitDate][projectName] = [];
          }
          commitsByDate[commitDate][projectName].push(commit);
        }
      });
    });
    
    // 为每个日期创建txt文件
    Object.keys(commitsByDate).forEach(date => {
      const dayProjects = commitsByDate[date];
      const dateFormatted = dayjs(date).format('YYYYMMDD');
      const txtFileName = `${dateFormatted}.txt`;
      const txtFilePath = path.join(txtOutputDir, txtFileName);
      
      // 生成txt文件内容
      let content = `${dateFormatted}\n`;
      content += `${config.name}\n`;
      content += `今日工作：\n`;
      
      // 按项目添加提交记录
      Object.keys(dayProjects).forEach(projectName => {
        const projectCommits = dayProjects[projectName];
        content += `${projectName}\n`;
        
        // 添加该项目的提交记录
        projectCommits.forEach((commit, index) => {
          // 移除时间戳，只保留提交信息
          const commitMessage = commit.message.replace(/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}\] /, '');
          content += `${index + 1}、${commitMessage}\n`;
        });
        
        content += '\n'; // 项目之间添加空行
      });
      
      // 写入文件
      fs.writeFileSync(txtFilePath, content, 'utf8');
      console.log(`成功创建每日工作记录: ${txtFilePath}`);
    });
    
  } catch (error) {
    console.error('创建每日工作记录失败:', error.message);
  }
}

/**
 * 将提交记录填写到Excel模板中
 * @param {string} excelFile - Excel文件路径
 * @param {object} config - 配置对象
 * @param {object} projectCommits - 按项目分组的提交记录
 * @param {object} weekInfo - 周信息（包含year, week, startDate, endDate）
 */
async function fillExcelWithCommits(excelFile, config, projectCommits, weekInfo = null) {
  try {
    // 创建工作簿实例
    const workbook = new ExcelJS.Workbook();
    
    // 读取Excel文件
    await workbook.xlsx.readFile(excelFile);
    
    // 获取第一个工作表
    const worksheet = workbook.worksheets[0];
    
    if (!worksheet) {
      throw new Error('无法找到工作表');
    }
    
    // 计算周数信息
    let week, year, startDate, endDate;
    if (weekInfo) {
      week = weekInfo.week;
      year = weekInfo.year;
      startDate = weekInfo.startDate;
      endDate = weekInfo.endDate;
    } else {
      // 使用当前周信息
      const now = dayjs();
      week = now.week();
      year = now.format('YYYY');
      startDate = now.startOf('week').format('YYYY-MM-DD');
      endDate = now.endOf('week').format('YYYY-MM-DD');
    }
    
    // 处理提交记录，按日期和项目分组
    const commitsByDate = {};
    let hasSaturdayCommits = false;
    let hasSundayCommits = false;
    let latestCommitDate = null;
    
    // 遍历每个项目的提交记录
    Object.keys(projectCommits).forEach(projectName => {
      const projectCommitsList = projectCommits[projectName];
      
      projectCommitsList.forEach(commit => {
        // 从提交记录中提取日期
        const dateMatch = commit.message.match(/\[(\d{4}-\d{2}-\d{2})/);
        if (dateMatch) {
          const commitDate = dateMatch[1];
          
          // 如果指定了周信息，只处理该周内的提交
          if (weekInfo) {
            const commitDayjs = dayjs(commitDate);
            if (commitDayjs.isBefore(startDate) || commitDayjs.isAfter(endDate)) {
              return; // 跳过不在该周范围内的提交
            }
          }
          
          // 检查是否有周六或周日的提交记录
          const commitDayjs = dayjs(commitDate);
          if (commitDayjs.day() === 6) { // 周六
            hasSaturdayCommits = true;
          } else if (commitDayjs.day() === 0) { // 周日
            hasSundayCommits = true;
          }
          
          // 记录最新的提交日期
          if (!latestCommitDate || commitDayjs.isAfter(latestCommitDate)) {
            latestCommitDate = commitDayjs;
          }
          
          if (!commitsByDate[commitDate]) {
            commitsByDate[commitDate] = {};
          }
          if (!commitsByDate[commitDate][projectName]) {
            commitsByDate[commitDate][projectName] = [];
          }
          commitsByDate[commitDate][projectName].push(commit);
        } else {
          // 如果没有日期信息，使用今天
          const today = dayjs().format('YYYY-MM-DD');
          if (!commitsByDate[today]) {
            commitsByDate[today] = {};
          }
          if (!commitsByDate[today][projectName]) {
            commitsByDate[today][projectName] = [];
          }
          commitsByDate[today][projectName].push(commit);
        }
      });
    });
    
    // 确定填报日期
    let reportDate;
    if (weekInfo) {
      // 如果指定了周信息，根据该周最后一次提交记录的时间确定填报日期
      if (latestCommitDate) {
        // 使用该周最后一次提交记录的日期作为填报日期
        reportDate = latestCommitDate.format('YYYY/MM/DD');
      } else {
        // 如果该周没有提交记录，使用周五作为默认填报日期
        const weekStart = dayjs(startDate);
        const friday = weekStart.add(4, 'day'); // 周五
        reportDate = friday.format('YYYY/MM/DD');
      }
    } else {
      // 使用当前日期
      reportDate = dayjs().format('YYYY/MM/DD');
    }
    
    // 填写基本信息
    // 第几周
    worksheet.getCell('D2').value = week;
    
    // 填报人
    worksheet.getCell('G2').value = config.name;
    
    // 填报日期
    worksheet.getCell('I2').value = reportDate;
    
    // 项目进度是否正常
    worksheet.getCell('C7').value = '正常';
    
    // 填写提交记录到表格中，按日期和项目组织
    let rowIndex = 11; // 从第11行开始填写
    
    // 按日期排序
    const sortedDates = Object.keys(commitsByDate).sort();
    
    sortedDates.forEach(date => {
      const dayProjects = commitsByDate[date];
      const dateFormatted = dayjs(date).format('YYYY/MM/DD');
      
      // 按项目排序
      const sortedProjects = Object.keys(dayProjects).sort();
      
      sortedProjects.forEach(projectName => {
        const projectCommits = dayProjects[projectName];
        
        // 合并该项目的所有提交记录
        const commitText = projectCommits.map((commit, index) => {
          // 移除时间戳，只保留提交信息
          const commitMessage = commit.message.replace(/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}\] /, '');
          return `${index + 1}、${commitMessage}`;
        }).join('\n');
        
        // 填写到对应的行
        worksheet.getCell(`B${rowIndex}`).value = rowIndex - 10; // 序号
        worksheet.getCell(`C${rowIndex}`).value = `[${projectName}] ${commitText}`; // 提交记录内容（包含项目名称）
        worksheet.getCell(`D${rowIndex}`).value = dateFormatted; // 计划开始时间
        worksheet.getCell(`E${rowIndex}`).value = dateFormatted; // 计划结束时间
        worksheet.getCell(`F${rowIndex}`).value = dateFormatted; // 实际开始时间
        worksheet.getCell(`G${rowIndex}`).value = dateFormatted; // 实际结束时间
        
        rowIndex++;
      });
    });
    
    // 保存文件
    await workbook.xlsx.writeFile(excelFile);
    console.log(`成功将提交记录填写到Excel文件: ${excelFile}`);
    
  } catch (error) {
    console.error('填写Excel文件失败:', error.message);
  }
}

/**
 * 从指定的 Git 仓库和分支中获取提交记录
 * @param {object} config - 配置对象
 * @param {string} [startDate] - 查询开始日期 (YYYY-MM-DD)
 * @param {string} [endDate] - 查询结束日期 (YYYY-MM-DD)
 * @returns {Promise<Array<object>>} 返回一个包含项目提交记录的数组
 */
async function getUserCommits(config, startDate, endDate) {
  const { name, email, gits } = config;
  const sDate = startDate ? dayjs(startDate).startOf('day') : dayjs().startOf('day');
  const eDate = endDate ? dayjs(endDate).endOf('day') : sDate.endOf('day');
  const dateRange = sDate.isSame(eDate, 'day') ? sDate.format('YYYY-MM-DD') : `${sDate.format('YYYY-MM-DD')} 至 ${eDate.format('YYYY-MM-DD')}`;

  console.log(`\n======================================================`);
  console.log(`正在获取 ${name} (${email}) 在 ${dateRange} 的提交记录...`);
  console.log(`======================================================`);

  const tempBaseDir = path.join(__dirname, 'temp_repos');
  if (!fs.existsSync(tempBaseDir)) fs.mkdirSync(tempBaseDir, { recursive: true });

  // 按项目分组的提交记录
  const projectCommits = {};

  // 创建一个Git实例
  const git = simpleGit();

  for (const project of gits) {
    console.log(`\n--- 项目: ${project.name} ---`);
    const branchesToSearch = project.branches;
    if (!branchesToSearch || branchesToSearch.length === 0) {
      console.log(`  -> 跳过项目，因未配置 "branches" 数组。`);
      continue;
    }

    // 初始化项目提交记录数组
    if (!projectCommits[project.name]) {
      projectCommits[project.name] = [];
    }

    // 用于去重的Set，存储提交的hash
    const commitHashes = new Set();

    for (const url of project.urls) {
      const repoName = url.split('/').pop().replace('.git', '');
      const repoDir = path.join(tempBaseDir, repoName);
      console.log(`\n  仓库: ${repoName}`);

      try {
        if (!fs.existsSync(repoDir)) {
           console.log(`    > 仓库不存在，正在克隆 (clone)...`);
           await git.clone(url, repoDir);
        } else {
          console.log(`    > 仓库已存在，正在拉取最新代码 (pull)...`);
          // 如果仓库存在，先切换到默认分支（通常是main或master）
          try {
            await git.cwd(repoDir).checkout('main');
          } catch (error) {
            try {
              await git.cwd(repoDir).checkout('master');
            } catch (error2) {
              console.log(`    > 无法切换到main或master分支，使用当前分支`);
            }
          }
          // 拉取最新代码
          await git.cwd(repoDir).pull();
        }
        
        console.log(`    > 正在更新所有远程分支信息 (fetch)...`);
        // 在执行命令前，使用 .cwd() 强制指定工作目录
        await git.cwd(repoDir).fetch('--all');

        // 遍历每个分支并切换到该分支获取提交记录
        for (const branch of branchesToSearch) {
          console.log(`    > 正在处理分支 [${branch}]...`);
          
          try {
            // 首先检查本地分支是否存在
            const localBranches = await git.cwd(repoDir).branch();
            const hasLocalBranch = localBranches.all.includes(branch);
            
            if (!hasLocalBranch) {
              console.log(`    > 本地分支 [${branch}] 不存在，尝试从远程拉取...`);
              
                             // 检查远程分支是否存在
               const remoteBranches = await git.cwd(repoDir).branch(['-r']);
               const remoteBranchName = `origin/${branch}`;
               const hasRemoteBranch = remoteBranches.all.includes(remoteBranchName);
              
              if (hasRemoteBranch) {
                console.log(`    > 找到远程分支 [${remoteBranchName}]，正在创建本地分支...`);
                await git.cwd(repoDir).checkout(['-b', branch, remoteBranchName]);
              } else {
                console.log(`    ! 远程分支 [${remoteBranchName}] 不存在，跳过该分支`);
                continue;
              }
            }
            
            // 切换到指定分支
            await git.cwd(repoDir).checkout(branch);
            
            const logOptions = {
              '--author': `<${email}>`,
              '--since': sDate.format('YYYY-MM-DD HH:mm:ss'),
              '--until': eDate.format('YYYY-MM-DD HH:mm:ss'),
              '--no-merges': null,
            };

            // 在当前分支上查找提交记录
            const logs = await git.cwd(repoDir).log(logOptions);

            if (logs.total > 0) {
              console.log(`    > 在 [${branch}] 分支中找到 ${logs.total} 条提交:`);
              logs.all.forEach((commit, index) => {
                // 检查是否已经存在相同的提交（通过hash去重）
                if (!commitHashes.has(commit.hash)) {
                  commitHashes.add(commit.hash);
                  const commitMessage = `[${dayjs(commit.date).format('YYYY-MM-DD HH:mm')}] ${commit.message}`;
                  console.log(`      ${index + 1}. ${commitMessage}`);
                  projectCommits[project.name].push({
                    message: commitMessage,
                    hash: commit.hash,
                    date: commit.date,
                    branch: branch,
                    repo: repoName
                  });
                } else {
                  console.log(`      ${index + 1}. ${commit.message} (重复提交，已跳过)`);
                }
              });
            } else {
              console.log(`    > 在 [${branch}] 分支中未找到相关提交。`);
            }
          } catch (error) {
            console.error(`    ! 处理分支 [${branch}] 时出错: ${error.message}`);
            console.log(`    > 跳过该分支，继续处理其他分支...`);
          }
        }
      } catch (error) {
        console.error(`  ! 处理仓库 ${repoName} 时出错:`, error.message);
      }
    }
  }

  // 过滤掉没有提交记录的项目
  const filteredProjectCommits = {};
  Object.keys(projectCommits).forEach(projectName => {
    if (projectCommits[projectName].length > 0) {
      filteredProjectCommits[projectName] = projectCommits[projectName];
    }
  });

  return filteredProjectCommits;
}


// 获取本周的提交记录
async function getWeeklyCommits(config) {
  // 计算本周的开始日期（周一）和结束日期（周日）
  const now = dayjs();
  const weekStart = now.startOf('week').format('YYYY-MM-DD');
  const weekEnd = now.endOf('week').format('YYYY-MM-DD');
  
  console.log(`\n生成本周 (${weekStart} 至 ${weekEnd}) 的提交记录汇总：`);
  
  // 获取本周的提交记录
  return await getUserCommits(config, weekStart, weekEnd);
}

// 执行主函数
async function main() {
  // 获取提交记录
  const config = readConfig();
  
  // 获取命令行参数
  const args = process.argv.slice(2);
  const command = args[0]; // 命令：daily, weekly, range
  
  let projectCommits = {};
  let excelFiles = [];
  
  if (command === 'weekly') {
    // 获取本周的提交记录
    projectCommits = await getWeeklyCommits(config);
    excelFiles = processWeeklyReport();
  } else if (command === 'range' && args.length >= 3) {
    // 获取指定日期范围的提交记录
    const startDate = args[1];
    const endDate = args[2];
    projectCommits = await getUserCommits(config, startDate, endDate);
    excelFiles = processWeeklyReport(startDate, endDate);
  } else {
    // 默认获取当天的提交记录
    const today = dayjs().format('YYYY-MM-DD');
    const date = command && command !== 'daily' ? command : today;
    console.log(`\n获取 ${date} 的提交记录：`);
    projectCommits = await getUserCommits(config, date);
    excelFiles = processWeeklyReport();
  }
  
  // 如果有提交记录，则创建文件
  if (Object.keys(projectCommits).length > 0) {
    // 创建Excel文件
    if (excelFiles && excelFiles.length > 0) {
      for (const excelFile of excelFiles) {
        console.log(`\n正在处理周报文件: ${excelFile.filePath}`);
        await fillExcelWithCommits(excelFile.filePath, config, projectCommits, excelFile.weekInfo);
      }
    }
    
    // 创建每日工作记录txt文件
    console.log(`\n正在创建每日工作记录txt文件...`);
    createDailyTxtFiles(config, projectCommits);
  } else {
    console.log('\n没有找到提交记录，跳过文件创建步骤。');
  }
}

// 运行主函数
main().catch(error => {
  console.error('程序执行失败:', error.message);
});